import struct

class CustomBMFont:
    def __init__(self, font_file):
        self.font_file = font_file
        self.font = open(font_file, 'rb')
        
        # 读取文件头
        header = self.font.read(16)
        if header[0:2] != b'BM':
            raise ValueError("Invalid BMF font file")
            
        self.version = header[2]
        self.map_mode = header[3]
        self.start_bitmap = struct.unpack('>I', b'\x00' + header[4:7])[0]
        self.font_size = header[7]
        self.bitmap_size = header[8]
        
        # 计算字符索引表大小
        self.index_table_size = (self.start_bitmap - 16) // 2
        
    def _find_char_index(self, char_code):
        """二分查找字符在索引表中的位置"""
        low = 0
        high = self.index_table_size - 1
        
        while low <= high:
            mid = (low + high) // 2
            self.font.seek(16 + mid * 2)
            mid_code = struct.unpack('>H', self.font.read(2))[0]
            
            if char_code == mid_code:
                return mid
            elif char_code < mid_code:
                high = mid - 1
            else:
                low = mid + 1
        return -1  # 未找到字符
        
    def get_char_bitmap(self, char):
        """获取字符的位图数据"""
        char_code = ord(char)
        index = self._find_char_index(char_code)
        
        if index == -1:
            # 返回一个默认方块(8x16)作为缺失字符显示
            return bytearray([0xFF]*16)
            
        # 读取位图数据
        self.font.seek(self.start_bitmap + index * self.bitmap_size)
        return bytearray(self.font.read(self.bitmap_size))
        
    def close(self):
        self.font.close()
def is_chinese(ch):
    """判断一个字符是否为中文字符"""
    if '\u4e00' <= ch <= '\u9fff' or \
       '\u3400' <= ch <= '\u4dbf' or \
       '\u20000' <= ch <= '\u2a6df':
        return True
    return False
def display_text(lcd, font, text, x_start, y_start, color, bg_color=None, spacing=0, line_spacing=0, max_width=800):
    """
    使用自定义字体显示文字(支持自动换行和中英混排)
    
    参数:
    lcd - LCD对象(需有point方法)
    font - CustomBMFont实例
    text - 要显示的文本
    x_start, y_start - 起始坐标
    color - 文字颜色
    bg_color - 背景颜色(None表示透明)
    spacing - 字符间距
    line_spacing - 行间距
    max_width - 最大行宽(像素)，None表示不限制
    """
    font_size = font.font_size
    bytes_per_row = (font_size + 7) // 8  # 每行占用的字节数
    x, y = x_start, y_start
    
    # 如果没有指定最大宽度，则使用屏幕宽度减去起始x坐标
    if max_width is None:
        max_width = lcd.width - x_start
    
    for char in text:
        # 处理换行符
        if char == '\n':
            y += font_size + line_spacing
            x = x_start
            continue
        if char == '\r':
            x += 2*font_size
            continue
        # 获取字符宽度(中文字符全宽，ASCII字符半宽)
        char_width = font_size if is_chinese(char) else font_size // 2
        
        # 检查是否需要换行
        if max_width is not None and x + char_width > x_start + max_width:
            y += font_size + line_spacing
            x = x_start
        
        # 获取字符位图
        bitmap = font.get_char_bitmap(char)
        
        # 绘制字符
        for row in range(font_size):
            for col in range(char_width if not is_chinese(char) else font_size):
                byte_idx = row * bytes_per_row + col // 8
                bit_mask = 0x80 >> (col % 8)
                
                if byte_idx < len(bitmap) and (bitmap[byte_idx] & bit_mask):
                    lcd.point(x + col, y + row, color)
                elif bg_color is not None:
                    lcd.point(x + col, y + row, bg_color)
        
        # 移动到下一个字符位置
        x += char_width + spacing